package com.hmall.order.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmall.common.feign.ItemServiceFeign;
import com.hmall.common.feign.UserServiceFeign;
import com.hmall.common.pojo.Address;
import com.hmall.common.pojo.Item;
import com.hmall.common.pojo.vo.ItemVo;
import com.hmall.order.context.BaseContext;
import com.hmall.order.mapper.OrderDetailMapper;
import com.hmall.order.mapper.OrderLogisticsMapper;
import com.hmall.order.mapper.OrderMapper;
import com.hmall.order.pojo.Order;
import com.hmall.order.pojo.OrderDetail;
import com.hmall.order.pojo.OrderLogistics;
import com.hmall.order.pojo.dto.OrderSubmitDto;
import com.hmall.order.service.IOrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.UUID;

@Slf4j
@Service
public class OrderService extends ServiceImpl<OrderMapper, Order> implements IOrderService {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private OrderDetailMapper orderDetailMapper;
    @Autowired
    private OrderLogisticsMapper orderLogisticsMapper;

    @Autowired
    private ItemServiceFeign itemServiceFeign;
    @Autowired
    private UserServiceFeign userServiceFeign;

    /**
     * 用户下单
     * @param orderSubmitDto
     * @return
     */
    @Transactional
    @Override
    public Long submit(OrderSubmitDto orderSubmitDto) {
        // 需要插入tb_order，tb_order_detail，tb_order_logistics
        Long userID = BaseContext.getCurrentId();

        // 远程调用查询商品信息
        ItemVo itemVo = itemServiceFeign.info(String.valueOf(orderSubmitDto.getItemId()));

        // 基于商品价格、购买数量计算商品总价：totalFee
        BigDecimal decimalNum = new BigDecimal(String.valueOf(orderSubmitDto.getNum()));
        BigDecimal decimalPrice = new BigDecimal(String.valueOf(itemVo.getPrice()));
        BigDecimal decimalTotalFee = decimalPrice.multiply(decimalNum);
        long totalFee = decimalTotalFee.longValue();

        // 封装Order对象，初识status为未支付,id由雪花算法生成
        Order order = Order.builder()
                .status(1)
                .totalFee(totalFee)
                .paymentType(orderSubmitDto.getPaymentType())
                .userId(userID)
                .build();

        baseMapper.insert(order);

        // 将商品信息、orderId信息封装为OrderDetail对象，写入tb_order_detail表
        OrderDetail orderDetail = OrderDetail.builder()
                .orderId(order.getId())
                .itemId(itemVo.getId())
                .num(orderSubmitDto.getNum())
                .title(itemVo.getName())
                .price(itemVo.getPrice())
                .spec(itemVo.getSpec())
                .image(itemVo.getImage())
                .build();

        orderDetailMapper.insert(orderDetail);

        // 根据addressId查询user-service服务，获取地址信息
        Address address = userServiceFeign.findAddressById(String.valueOf(userID), orderSubmitDto.getAddressId());

        // 将地址封装为OrderLogistics对象，写入tb_order_logistics表，id和orderid一一对应需要手动赋值
        orderLogisticsMapper.insert(OrderLogistics.builder()
                .orderId(order.getId())
                .logisticsNumber(String.valueOf(order.getId()))
                .logisticsCompany(address.getContact()+":"+itemVo.getName())
                .contact(address.getContact())
                .phone(address.getMobile())
                .province(address.getProvince())
                .city(address.getCity())
                .town(address.getTown())
                .street(address.getStreet())
                .build());

        // 下单后减少库存
        itemServiceFeign.update(
                Item.builder()
                    .id(itemVo.getId())
                    .stock(itemVo.getStock()-1)
                    .build()
        );

        // 30分钟没支付，删除订单，并返回库存
        Message message = MessageBuilder
                .withBody(String.valueOf(order.getId()).getBytes(StandardCharsets.UTF_8))
                .setExpiration("60000")
                .build();
        // 消息ID，需要封装到CorrelationData中
        CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
        correlationData.getFuture().addCallback(
                result -> {
                    if(result.isAck()){
                        // 3.1.ack，消息成功
                        log.info("消息发送成功, ID:{}", correlationData.getId());
                    }else{
                        // 3.2.nack，消息失败
                        log.error("消息发送失败, ID:{}, 原因{}",correlationData.getId(), result.getReason());
                    }
                },
                ex -> log.error("消息发送异常, ID:{}, 原因{}",correlationData.getId(),ex.getMessage())
        );

        // 发送消息
        rabbitTemplate.convertAndSend("order", "ispay", message, correlationData);

        return order.getId();
    }

    @Override
    public List<OrderDetail> orderDetailByOrderID(Serializable orderID) {
        LambdaQueryWrapper<OrderDetail> queryWrapper = new LambdaQueryWrapper<OrderDetail>()
                .eq(OrderDetail::getOrderId, orderID);
        return orderDetailMapper.selectList(queryWrapper);
    }
}
